#ifndef TEMPLE_UTIL_QUEUE_H_
#define TEMPLE_UTIL_QUEUE_H_
#if 1

#include "util/stdc.h"
#include <list>
#include <mutex>
#include <condition_variable>
namespace util {

template<class T>
class Queue
{
public:
	inline void push(const T &obj)
    {
        std::unique_lock<std::mutex> lock(mutex);
        list.push_back(obj);
        cond.notify_one();
    }

	inline void push(T &&obj)
    {
        std::unique_lock<std::mutex> lock(mutex);
        list.push_back(std::move(obj));
        cond.notify_one();
    }

	inline void pop(T &obj)
    {
        std::unique_lock<std::mutex> lock(mutex);
        cond.wait_for(lock, [&](){return !list.empty();});
        obj = std::move(list.front());
        list.pop_front();
    }

	inline int wait(T &obj, int msec)
    {
        std::unique_lock<std::mutex> lock(mutex);

        if (!cond.wait_for(lock, std::chrono::milliseconds(msec), [&](){return !list.empty();}))
            return 1;

        obj = std::move(list.front());
        list.pop_front();
        return 0;
    }

	inline void roll_back(const T &obj)
    {
        std::unique_lock<std::mutex> lock(mutex);
        list.push_front(obj);
        cond.notify_one();
    }

	inline void roll_back(T &&obj)
    {
        std::unique_lock<std::mutex> lock(mutex);
        list.push_front(std::move(obj));
        cond.notify_one();
    }

    inline int size()
    {
        std::unique_lock<std::mutex> lock(mutex);
        return list.size();
    }

private:
	std::list<T> list;
    std::mutex mutex;
	std::condition_variable cond;
};

}

#else

#if 0

#include "util/stdc.h"
#include "util/time.h"
#include <pthread.h>
#include <list>
namespace util {

template<class T>
class Queue
{
public:
	inline Queue()
    {
#if 0
    	pthread_mutexattr_t ma;
    	pthread_mutexattr_init(&ma);
    	pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
    	pthread_mutex_init(&lock, &ma);

        pthread_condattr_t ca;
        pthread_condattr_init(&ca);
        pthread_condattr_setclock(&ca, CLOCK_REALTIME);
        pthread_cond_init(&cond, &ca);
#endif
        pthread_mutex_init(&lock, NULL);
    	pthread_cond_init(&cond, NULL);
    }

    inline ~Queue()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

	inline void push(const T &obj)
    {
        pthread_mutex_lock(&lock);
        list.push_back(obj);
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&cond);
    }

	inline void push(T &&obj)
    {
        pthread_mutex_lock(&lock);
        list.push_back(std::move(obj));
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&cond);
    }

	inline void pop(T &obj)
    {
        pthread_mutex_lock(&lock);
        while(list.empty())
            pthread_cond_wait(&cond, &lock);
        obj = std::move(list.front());
        list.pop_front();
        pthread_mutex_unlock(&lock);
    }

	inline int wait(T &obj, int msec)
    {
        pthread_mutex_lock(&lock);

#ifdef WIN32
        struct _timeb tb;
        _ftime(&tb);
#else
        struct timeb tb;
        ftime(&tb);
#endif

        struct timespec ts;
        ts.tv_sec = tb.time + msec/1000;
        ts.tv_nsec = (tb.millitm + msec%1000)*1000*1000;

        while (list.empty())
        {
            if (pthread_cond_timedwait(&cond, &lock, &ts))
            {
                pthread_mutex_unlock(&lock);
                return 1;
            }
        }

        obj = std::move(list.front());
        list.pop_front();
        pthread_mutex_unlock(&lock);
        return 0;
    }

	inline void roll_back(const T &obj)
    {
        pthread_mutex_lock(&lock);
        list.push_front(obj);
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&cond);
    }

	inline void roll_back(T &&obj)
    {
        pthread_mutex_lock(&lock);
        list.push_front(std::move(obj));
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&cond);
    }

    inline int size()
    {
        int len;
        pthread_mutex_lock(&lock);
        len = list.size();
        pthread_mutex_unlock(&lock);
        return len;
    }

private:
    pthread_mutex_t lock;
	pthread_cond_t cond;
	std::list<T> list;
};

}

#else

#include "util/stdc.h"
#include <pthread.h>
#include <semaphore.h>
namespace util {

template<class T>
class Queue
{
public:
	inline Queue()
	{
		pthread_mutexattr_t a;
		pthread_mutexattr_init(&a);
		pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
		pthread_mutex_init(&lock, &a);
		sem_init(&sem, 0, 0);
	}

	inline ~Queue()
	{
		pthread_mutex_destroy(&lock);
		sem_destroy(&sem);
	}

	inline void push(const T &obj)
	{
		pthread_mutex_lock(&lock);
		list.push_back(obj);
		pthread_mutex_unlock(&lock);
		sem_post(&sem);
	}

	inline void pop(T &obj)
	{
		sem_wait(&sem);
		pthread_mutex_lock(&lock);
		obj = list.front();
		list.pop_front();
		pthread_mutex_unlock(&lock);
	}

	inline int wait(T &obj, int msec)
    {
#ifdef WIN32
        struct _timeb tb;
        _ftime(&tb);
#else
        struct timeb tb;
        ftime(&tb);
#endif

        struct timespec ts;
        ts.tv_sec = tb.time + msec/1000;
        ts.tv_nsec = (tb.millitm + msec%1000)*1000*1000;

		if (sem_timedwait(&sem, &ts))
		{
			return 1;
		}

        pthread_mutex_lock(&lock);
		obj = list.front();
		list.pop_front();
        pthread_mutex_unlock(&lock);
        return 0;
    }

	inline void rollback(const T &obj)
	{
		pthread_mutex_lock(&lock);
		list.push_front(obj);
		pthread_mutex_unlock(&lock);
		sem_post(&sem);
	}

    inline int size()
    {
        int len;
        pthread_mutex_lock(&lock);
        len = list.size();
        pthread_mutex_unlock(&lock);
        return len;
    }

private:

    pthread_mutex_t lock;
	sem_t sem;
	std::list<T> list;
};

}
#endif

#endif
#endif //TEMPLE_UTIL_QUEUE_H_
